package com.hugoo.imp.buzz;

import com.hugoo.core.Conf;
import com.hugoo.core.db.Call;
import com.hugoo.core.db.ImpProc;
import com.hugoo.core.util.GZipUtils;
import com.hugoo.core.util.TL;
import com.hugoo.imp.buzz.mo.ColumnInfo;
import java.io.File;
import java.sql.CallableStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;

/**
 *
 * @author Lovelock.Chan
 */
public abstract class ImpInfo extends FileInfo {

    protected String kf;
    protected String impFilePath;
    private String pre, lst;
    private Map<String, String> para;

    private void pckcl(String[] c, StringBuilder sb, StringBuilder sd, boolean fl) {
        String d[];
        for (String l : c) {
            if (TL.isEmpty(l)) {
                continue;
            }
            d = l.trim().split(":");
            if (d.length != 2) {//传入结构必须为2元结构
                continue;
            }
            sb.append(",").append(d[0]);
            if (fl) {
                sd.append(",?");
            } else {
                sd.append(",").append(d[1]);
            }
        }
    }

    public ImpInfo(String _sid, String impFilePath, String _scod, Map<String, String> parax) {
        super(_sid, _scod, null);
        this.para = parax;
        if (para == null) {
            para = new HashMap();
        }

        {//初始化参数块
            para.put("__sid", _sid);//模块编码
            para.put("__scod", _scod);//批次编码
        }
        this.impFilePath = impFilePath;
        _initImpSql();

    }

    private void _initImpSql() {
        StringBuilder sb = new StringBuilder(), sd = new StringBuilder(), ss = new StringBuilder();
        //~~~~~~~~~~~~~~包装导入数据列~~~~~~~~~~~~~~~~~~~
        this.pckcl(_cols, sb, sd, true);
        //~~~~~~~~~~~~~~包装系统数据列~~~~~~~~本部分数据不做其它的处理~~~~~~~~~~~
        String alColumn = getAlSysColumn();
        if (TL.isNotEmpty(alColumn)) {
            String[] _cols = alColumn.split(",");
            this.pckcl(_cols, sb, sd, false);
        }
        //~~~~~~~~~~~~~~包装完成~~~~~~~~~~~~~~~~~~~
        if (sb.length() > 1) {
            kf = sb.replace(0, 1, "insert into " + table_name + "(").append(") values (").
                    append(sd.substring(1)).append(")").toString();
        }
    }

    public String getAlSysColumn() {
        StringBuilder sb = new StringBuilder();
        String rl = Conf.getImpProp(_sid, Conf.IMP._imp_table_al_column);
        if (TL.isNotEmpty(rl)) {
            sb.append(rl).append(",");
        }
        switch (dbt) {
            case ORACLE:
                sb.append(X__SID + ":'").append(_sid).append("'," + X__SCOD + ":'").append(scod).append("'," + X__IMPDT + ":").append("sysdate");
                break;
            case SQL_SERVER:
                sb.append(X__SID + ":'").append(_sid).append("'," + X__SCOD + ":'").append(scod).append("'," + X__IMPDT + ":").append("getdate()");
                break;
        }
        return sb.toString();
    }

    @Override
    protected void __buildSysColumn(List<ColumnInfo> col) {
        String sysCol[] = getAlSysColumn().split(","), d[];
        ColumnInfo ci;
        for (String sc : sysCol) {
            d = sc.split(":");
            if (d.length == 2) {
                ci = new ColumnInfo(d[0], sys_sk, d[1]);
                col.add(ci);//包装列
            } else {
                log.info("设置的系统缺省列【" + sc + "】无效。");
            }
        }
    }

    public void lstProcFile(String imd) {
        if (TL.isEmpty(imd)) {
            //do noting
        } else if (imd.endsWith("D")) {
            deleteFile();
        } else if (imd.endsWith("Z")) {
            compressFile();
        }
    }

    protected void deleteFile() {
        File f = new File(impFilePath);
        if (f.exists()) {
            f.delete();
            log.info("删除上传文件【" + impFilePath + "】成功！");
        }
    }

    protected void compressFile() {
        File f = new File(impFilePath);
        if (f.exists()) {
            try {
                GZipUtils.compress(f);
                log.info("归档成功！");
            } catch (Exception e) {
                log.info("压缩文件出现异常！", e);
            }
        }
    }

    class X {

        final int no, stype;
        final String name;

        public X(int no, int stype, String name) {
            this.no = no;
            this.stype = stype;
            this.name = name;
        }
    }

    private String xproc(String pre, List<X> l) {
        String t[] = pre.split("\\|");
        if (t.length > 1) {
            for (int i = 1; i < t.length; i++) {
                if (TL.isEmpty(t[i])) {
                    log.warn("配置的参数值不完整！");
                    continue;
                }
                if (t[i].startsWith("-")) {
                    t[i] = t[i].substring(1);
                    l.add(new X(i, 1, t[i]));
                } else if (t[i].startsWith("+")) {
                    t[i] = t[i].substring(1);
                    l.add(new X(i, 2, t[i]));
                } else {
                    log.warn("配置的参数值不完整！");
                }
            }
        }
        pre = t[0].startsWith("call ") ? t[0] : "call " + t[0];
        return pre;
    }
    private List<X> prl = new ArrayList<X>(), lsl = new ArrayList<X>();

    public boolean hasPreProc() {
        pre = Conf.getImpProp(_sid, Conf.IMP._imp_pre_op);
        if (TL.isEmpty(pre)) {
            return false;
        }
        pre = pre.trim();
        pre = xproc(pre, prl);
        return true;
    }

    private void v(CallableStatement pc, List<X> prl, Log log) throws SQLException {
        for (X x : prl) {
            if (x.stype == 1) {
                String deval = para.get(x.name);
                log.info("传入参数值:【" + deval + "】");
                pc.setString(x.no, deval);
            } else {
                log.info("注册输入参数：【" + x.no + "】");
                pc.registerOutParameter(x.no, java.sql.Types.VARCHAR);
            }
        }
        pc.execute();
        for (X x : prl) {
            if (x.stype == 2) {
                String vl = pc.getString(x.no);
                log.info(x.name + ":" + vl);
                para.put(x.name, vl);
            }
        }
    }

    public Call preProc() {
        return new Call() {
            @Override
            public void proc(CallableStatement pc, Log log) throws SQLException {
                v(pc, prl, log);
            }

            @Override
            public String procSql() {
                return pre;
            }
        };
    }

    public boolean hasLstProc() {
        lst = Conf.getImpProp(_sid, Conf.IMP._imp_lst_op);
        if (TL.isEmpty(lst)) {
            return false;
        }
        log.info("存在导入后事件处理。");
        lst = lst.trim();
        lst = xproc(lst, lsl);
        return true;
    }

    public Call lstProc() {
        return new Call() {
            @Override
            public void proc(CallableStatement pc, Log log) throws SQLException {
                v(pc, lsl, log);
            }

            @Override
            public String procSql() {
                return lst;
            }
        };
    }

    public abstract ImpProc impProc();

    private String tableName() {
        return this.table_name;
    }
    private List<String> lsq = new ArrayList();

    public boolean validateSysDb() throws SQLException {
        StringBuilder sb = null;
        List<String> lv = new ArrayList();
        if (needCTable) {
            sb = new StringBuilder();
            sb.append("create table ").append(tableName()).append("(");
        }
        for (ColumnInfo c : col) {
            if (c.exists()) {
                continue;
            }
            if (needCTable) {
                sb.append(c.getName());
                switch (dbt) {
                    case ORACLE:
                        lv.add("COMMENT ON COLUMN " + tableName().trim() + "." + c.getName().trim() + " IS '" + c.getDesc() + "'");
                        break;
                    case SQL_SERVER:
                        break;
                }
                // 
            } else {
                sb = new StringBuilder();
                sb.append("ALTER TABLE ").append(tableName()).append(" ADD (").append(c.getName());
                switch (dbt) {
                    case ORACLE:
                        lv.add("COMMENT ON COLUMN " + tableName().trim() + "." + c.getName().trim() + " IS '" + c.getDesc() + "'");
                        break;
                    case SQL_SERVER:
                        break;
                }
            }
            if (sys_sk.equals(c.getDesc())) {
                if (X__IMPDT.equals(c.getName())) {
                    switch (dbt) {
                        case ORACLE:
                            sb.append(" date");
                            break;
                        case SQL_SERVER:
                            sb.append(" datetime");
                            break;
                    }
                } else {
                    sb.append(" varchar(100)");
                }
            } else {
                if ("varchar".equalsIgnoreCase(c.getType())) {
                    if (c.getMaxLength() > 0) {
                        sb.append(" varchar(").append(c.getMaxLength()).append(")");
                    } else {
                        sb.append(" varchar(").append(100).append(")");
                    }
                } else if ("number".equalsIgnoreCase(c.getType())) {
                    sb.append(" number");
                } else if ("date".equalsIgnoreCase(c.getType())) {
                    sb.append(" date");
                } else {
                    sb.append(" varchar(100)");
                }

            }
            if (needCTable) {
                sb.append(",");
            } else {
                lsq.add(sb.append(')').toString());
                //增加注释
                lsq.addAll(lv);
            }
        }
        if (needCTable) {
            sb.replace(sb.length() - 1, sb.length(), ")");
            lsq.add(sb.toString());
            //增加注释
            lsq.addAll(lv);
        }
        return lsq.isEmpty();
    }

    /**
     * 预数据库，处理语句， 用于更新数据库，数据表结构操作！
     *
     * @return
     */
    public List<String> procDataSql() {
        return lsq;
    }
}
